﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Text;
using System.Windows.Media;

namespace SharpSoft.WPF.Controls
{
    /// <summary>
    /// 贝塞尔曲线辅助工具
    /// </summary>
   public static  class BezierHelper
    {
        /// <summary>
        /// 获取经过一系列点的贝塞尔曲线
        /// </summary>
        /// <param name="points"></param>
        /// <returns></returns>
        public static PathGeometry GetBezierCurve(Point[] points)
        {
            if (points==null)
            {
                throw new ArgumentNullException(nameof(points));
            }
            if (points.Length<4)
            {
                throw new Exception("生成贝塞尔曲线至少需要4个点。");
            }
            PathGeometry p = new PathGeometry();
            PathFigure pathFigure = new PathFigure();
            p.Figures.Add(pathFigure);
            pathFigure.StartPoint = points[0];

            for (int i = 1; i < points.Length-1; i++)
            {
               var s= GetBezierSegment(points[i], points[i - 1], points[i + 1],i+2>=points.Length? points[i + 1]:points[i + 2]);
                pathFigure.Segments.Add(s);
            }
            return p;
        
        }


        private static BezierSegment GetBezierSegment(Point currentPt, Point lastPt, Point nextPt1, Point nextPt2)
        {
            //计算中点
            var lastC = GetCenterPoint(lastPt, currentPt);
            var nextC1 = GetCenterPoint(currentPt, nextPt1); //贝塞尔控制点
            var nextC2 = GetCenterPoint(nextPt1, nextPt2);

            //计算相邻中点连线跟目的点的垂足
            //效果并不算太好，因为可能点在两个线上或者线的延长线上，计算会有误差
            //所以就直接使用中点平移方法。
            //var C1 = GetFootPoint(lastC, nextC1, currentPt);
            //var C2 = GetFootPoint(nextC1, nextC2, nextPt1);


            //计算“相邻中点”的中点
            var c1 = GetCenterPoint(lastC, nextC1);
            var c2 = GetCenterPoint(nextC1, nextC2);


            //计算【"中点"的中点】需要的点位移
            var controlPtOffset1 = currentPt - c1;
            var controlPtOffset2 = nextPt1 - c2;

            //移动控制点
            var controlPt1 = nextC1 + controlPtOffset1;
            var controlPt2 = nextC1 + controlPtOffset2;

            //如果觉得曲线幅度太大，可以将控制点向当前点靠近一定的系数。
            controlPt1 = controlPt1 + 0 * (currentPt - controlPt1);
            controlPt2 = controlPt2 + 0 * (nextPt1 - controlPt2);

            var bzs = new BezierSegment(controlPt1, controlPt2, nextPt1, true);
            return bzs;
        }

        private static Point GetCenterPoint(Point lastC, Point nextC1)
        {
            return new Point((lastC.X + nextC1.X) / 2, (lastC.X + nextC1.Y) / 2);
        }
    }
}
